package com.cyzy.mq;

import com.cyzy.dto.Result;
import com.cyzy.service.SecKillService;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.checkerframework.checker.units.qual.A;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import java.sql.Timestamp;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static net.minidev.asm.DefaultConverter.convertToLong;

@Component
@RocketMQMessageListener(topic = "seckill-topic",consumerGroup = "consumer-seckill")
public class seckillConsumer implements RocketMQListener<Map<String,Object>> {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private SecKillService secKillService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Override
    public void onMessage(Map<String,Object> map) {//有消息自动回调这个onMess
        System.out.println("接受到消息:"+map);
        String queryId = (String) map.get("queryId");
        System.out.println("queryId的值为"+queryId);

        Long seckillId = convertToLong(map.get("seckillId"));
        Long studentId = convertToLong(map.get("studentId"));
        String redisKey = "seck_" + seckillId;
        // 1. 获取Redisson分布式锁
        RLock lock = redissonClient.getLock("lock:seckill:" + seckillId);

        try {
            if (lock.tryLock(100,30000, TimeUnit.MICROSECONDS)){
                //2.检查Redis库存
                Long size = redisTemplate.opsForSet().size(redisKey);
                if (size!=null&&size>0){
                    //3.减少库存并获取激活码
                    Object activateCode = redisTemplate.opsForSet().pop(redisKey);

                    try {
                        // 执行数据库操作
                        executeInTransaction(map, redisKey, activateCode);
                        Long orderId = (Long) map.get("orderId");
                        System.out.println("orderId的订单为:"+orderId);
                        // 存储成功结果
                        redisTemplate.opsForValue().set(
                                "seckill:result:" + queryId,
                                Result.ok()
                                        .message("秒杀成功")
                                        .data("orderId", orderId),
                                5,
                                TimeUnit.MINUTES
                        );
                    } catch (Exception e) {
                        // 回滚库存并存储失败结果
                        redisTemplate.opsForSet().add(redisKey, activateCode);
                        redisTemplate.opsForValue().set(
                                "seckill:result:" + queryId,
                                Result.error().message("秒杀失败：" + e.getMessage()),
                                5,
                                TimeUnit.MINUTES
                        );
                    }
                }else {
                    // 7. 库存为空时更新状态
                    secKillService.updateSeckillStatus(seckillId, "已结束");
                    redisTemplate.opsForValue().set(
                            "seckill:result:" + queryId,
                            Result.error().message("库存已售罄"),
                            5,
                            TimeUnit.MINUTES
                    );
                }
            }else{
                // 获取锁失败
                redisTemplate.opsForValue().set(
                        "seckill:result:" + queryId,
                        Result.error().message("库存已售罄"),
                        5,
                        TimeUnit.MINUTES
                );
            }
        }catch (Exception e){
            // 处理异常
            redisTemplate.opsForValue().set(
                    "seckill:result:" + queryId,
                    Result.error().message("系统异常：" + e.getMessage()),
                    5,
                    TimeUnit.MINUTES
            );
        }finally {
            // 8. 确保释放锁
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }


    }
    private void executeInTransaction(Map<String, Object> map, String redisKey, Object activateCode) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    map.put("activateCode", activateCode);
                    map.put("createTime", new Timestamp(System.currentTimeMillis()));
                    Long i = secKillService.insertOrderBySecKill(map);
                    map.put("orderId",i);
                    System.out.println("用户的订单ID:"+i);
                    secKillService.insertStudentCourse(map);
                    Long size = redisTemplate.opsForSet().size(redisKey);
                    if (size<=0){
                        System.out.println("卖空了");
                    }

                } catch (Exception e) {
                    status.setRollbackOnly();
                    redisTemplate.opsForSet().add(redisKey, activateCode);
                    throw new RuntimeException("数据库操作失败，已恢复库存", e);
                }
            }
        });
    }
}
